/*+***********************************************************************************
 Filename: hal_basic.v
 Description:
   Basic HAL functions for my TangPrimer20kDock based mcu. (03_mcu_sparrowrvcore_02)

 Modification:
   2024.05.25 Creation    H.Zheng
   2025.07.18 modified for e01_mcu02_mycorea_012(enable more interrupt related csr)
   2025.08.17 modified for 9k_mcu01_mycore_v01 (change memory map, no interrupt)
   2025.09.01 modified for 9k_mcu02_mycore02, add intctrl

Copyright (C) 2024-2025  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/
#include "hal_basic.h"

//for my peripheral
#define GPIO_ODR      *((volatile unsigned int *)0x10000000)
#define GPIO_IDR      *((volatile unsigned int *)0x10000004)
#define UART_TXD      *((volatile unsigned int *)0x10000100)
#define UART_RXD      *((volatile unsigned int *)0x10000100)
#define UART_RX_VALID   *((volatile unsigned int *)0x10000104)
#define UART_TX_BUSY   *((volatile unsigned int *)0x10000108)
#define TIMER_CTRL    *((volatile unsigned int *)0x10000200)
#define TIMER_COUNTER *((volatile unsigned int *)0x10000204)
#define TIMER_TOP     *((volatile unsigned int *)0x10000208)
#define TIMER_OVERFLOW_FLAG     *((volatile unsigned int *)0x1000020c)

#define PERI_EFFECT_INT_REQ     *((volatile unsigned int *)0x1000ff00)
#define PERI_INT_MASK     *((volatile unsigned int *)0x1000ff04)
#define PERI_PENDING_INT_REQ     *((volatile unsigned int *)0x1000ff08)

#define PERI_INT_MASK_VALUE_TIMER 0x01
#define PERI_INT_MASK_VALUE_UART  0x02

/**
 * GPIO
 */
void setLedValue(unsigned int vValue) {
  GPIO_ODR = vValue;
}

unsigned int getLedValue() {
  return GPIO_ODR;
}

int buttonPushed(){
    unsigned int i, button;
    i = GPIO_IDR&0x07;
    if (i== 0x07)
        return 0;
    else if ((i&0x01)== 0)
        button=1;
    else if ((i&0x02)== 0)
        button= 2;
    else if ((i&0x04)== 0)
        button= 3;
    else
        button = 0;
    //wait for button released
    while ((GPIO_IDR&0x07)!= 0x07) {
    }
    //
    return button;
}

/**
 * TIMER
 */
void setTimerTopValue(unsigned int vValue) {
  TIMER_TOP = vValue;
}

void startTimer() {
  TIMER_CTRL = 0x01;
}

unsigned int getTimeoutFlag(){
    return TIMER_OVERFLOW_FLAG;
}

void delayMs(unsigned int period){
    TIMER_CTRL = 0;
    TIMER_TOP = (SYSTEM_CLOCK_FREQ/1000)*period;
    TIMER_COUNTER = 0;
    TIMER_CTRL = 1;
    while (TIMER_OVERFLOW_FLAG == 0) {
    }
}

/**
 * UART
 */
void _putchar(char character){
    while (UART_TX_BUSY!=0){
    }
    UART_TXD = character;
}

void uartSendStr(const char *str) {
    unsigned int pos;
    for (pos=0;pos<128;pos++) {
      if (*(str+pos)!=0) {
          _putchar(*(str+pos));
      }else{
        break;
      }
    }
}

void uartSend(unsigned int vData) {
  _putchar(vData);
}

//blocking function: return until receive byte
unsigned int uartReceive() {
    while (!UART_RX_VALID){
    }
    return UART_RXD;
}

unsigned int getUartRxFlag(){
    return UART_RX_VALID;
}


/**
 * Interrupt
 */
void enableGlobalInt() {
  __asm__ __volatile__("csrsi  mstatus,0x08");
}

void enableTimerInt() {
  PERI_INT_MASK |= PERI_INT_MASK_VALUE_TIMER;
}

void enableUartRxvalidInt() {
  PERI_INT_MASK |= PERI_INT_MASK_VALUE_UART;
}


/**
 * external interrupt handler
 */

//default timer overflow handler
unsigned int gTimeoutFlag;

__attribute__((weak)) void handler_timer_overflow() {
    gTimeoutFlag = TIMER_OVERFLOW_FLAG;
}

//default uart rxvalid handler
unsigned int gUartRxData;
unsigned int gUartRxDataFlag;

__attribute__((weak)) void handler_uart_rxvalid() {
  gUartRxData = UART_RXD;
  gUartRxDataFlag = 1;
}

//external interrupt handler
void handler_interrupt_ex() {
  unsigned int request;
  request = PERI_EFFECT_INT_REQ;
  if (request & PERI_INT_MASK_VALUE_TIMER) {
    handler_timer_overflow();
  }
  if (request & PERI_INT_MASK_VALUE_UART) {
    handler_uart_rxvalid();
  }

}
